home *** CD-ROM | disk | FTP | other *** search
- /* ESCAPE.C
- ************************************************************************
- * *
- * PC Scheme/Geneva 4.00 Borland C code *
- * *
- * (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT *
- * (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva *
- * *
- *----------------------------------------------------------------------*
- * *
- * Handle all %ESCAPE extensions *
- * *
- *----------------------------------------------------------------------*
- * *
- * Created by: M. Vuilleumier Date: 1992 *
- * Revision history: *
- * - 18 Jun 92: Renaissance (Borland Compilers, ...) *
- * *
- * ``In nomine omnipotentii dei'' *
- ************************************************************************/
-
- #include <ctype.h>
- #include <string.h>
- #include <dos.h>
- #include <dir.h>
- #include <math.h>
- #include <io.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include "scheme.h"
- #ifdef __cplusplus
- extern "C" void _Cdecl textmode( int __newmode );
- #else
- void _Cdecl textmode( int __newmode );
- #endif
-
- #define DEFSTR 100
- // the default string size scanf can return
- /************************************************************************/
- /* Scheme to Borland C (or assembly langauge) Interface */
- /* */
- /* Purpose: To provide the ability for a Scheme user to link to low */
- /* level routines not written in Scheme. */
- /* */
- /* Description: This interface allows linkage to routines written in */
- /* Borland C, or assembly langauge routines which use the */
- /* Borland C linkage conventions. */
- /* */
- /* Limitations: This interface may be used to call routines which */
- /* accept up to 60 arguments of the Borland C types: */
- /* */
- /* long (32 bits integers) */
- /* char */
- /* char * (zero terminated string) */
- /* double (64 bits float) */
- /* */
- /* and which return a single Scheme value of one of the */
- /* following types: */
- /* */
- /* fix/bignum (up to 32 bits) */
- /* flonum */
- /* character */
- /* string */
- /* #t or '() */
- /* */
- /* The C and/or assembly language routines may have side */
- /* effects and save state information, but they may not */
- /* have access to, or modify, the state of the Scheme */
- /* runtime (except through the passing of parameters). */
- /* */
- /* How to Use: */
- /* */
- /* 1. Compile the routine you wish to call using the medium model */
- /* (large code, small data) Borland C compiler. */
- /* */
- /* 2. Modify this routine (ESCAPE.C) as follows, and compile it */
- /* with the medium model Borland C compiler. */
- /* */
- /* a. Add a declaration to indicate the type of the value to */
- /* be returned by your external routine, e.g., */
- /* */
- /* char *dir1( char *, char * ); */
- /* */
- /* Here, the function "dir1" is declared to return */
- /* (char *), which is the C representation for a character */
- /* string. */
- /* */
- /* b. Add an entry in the "switch" statement to call your */
- /* routine. You must explicitly indicate the type of each */
- /* argument you pass, as well as the value you wish to be */
- /* returned to Scheme. */
- /* */
- /* Argument values may be obtained and converted to the */
- /* appropriate type using a specified member of LINKARG structure: */
- /* */
- /* arg[n].item.i is the n-th argument as an integer (long) */
- /* arg[n].item.b is the n-th argument as a boolean (short) */
- /* arg[n].item.c is the n-th argument as a character (char) */
- /* arg[n].item.f is the n-th argument as a float (double) */
- /* arg[n].item.s is the n-th argument as a string (char *) */
- /* */
- /* The index of last valid argument is stored in lastArg */
- /* The type of the argument is stored in arg[n].type and is either: */
- /* */
- /* BOOLEAN, INTEGER, FLOAT, CHARACTER or STRING */
- /* */
- /* Value must be returned using one of the following assignement */
- /* */
- /* result->i = any_long_variable */
- /* result->b = any_short_variable */
- /* result->c = any_char_variable */
- /* result->f = any_double_variable */
- /* result->s = any_char*_variable */
- /* */
- /* and type of return value should be returned as follow : */
- /* */
- /* return NOVALUE; if scheme return value is undefined */
- /* return INTEGER; if scheme return value is an integer */
- /* return BOOLEAN; if scheme return value is a boolean */
- /* return CHARACTER; if scheme return value is a character */
- /* return FLOAT; if scheme return value is a float */
- /* return STR; if scheme return value is a string */
- /* return STRorNIL; if scheme return value is either a */
- /* string or NIL if char* = nil */
- /* */
- /* You are NOT responsable for freeing the space used by string */
- /* parameters or return value. This will be done by PCS. But you are */
- /* not allowed to modify the argument table, since PCS could loose */
- /* trace of the data he might want to free. Return value are freed */
- /* according to the declared return type (so ensure it is correct). */
- /* */
- /* c. The case number in step b is the "function code" which */
- /* is used to invoke the function. The function code must */
- /* always be an integer and must be the first operand */
- /* passed the "%esc" Scheme functions. The other operands follow */
- /* the function code in the order expected by the called routine. */
- /* */
- /* For example, to call the "dir1" function with one operand, we code: */
- /* */
- /* (%esc 0 "string") */
- /* */
- /* where the first operand (0) is the function code and */
- /* "string" is the character string to be passed as the */
- /* only argument. */
- /* */
- /* d. To provide a more meaningful calling sequence and to */
- /* check for correct parameters, a Scheme routine should */
- /* be defined for each function to be called. These */
- /* functions are normally placed in the SCHEME.INI file, */
- /* but may be installed "permanently" for a given */
- /* application by converting them to fast-load format and */
- /* appending them to the FRONT of the COMPILER.FSL file, */
- /* which is automatically loaded when PCS begins. */
- /* */
- /* A sample Scheme function for the "dir1" function is: */
- /* */
- /* (define dir1 */
- /* (lambda (filespec) */
- /* (if (string? filespec) */
- /* (%esc 0 filespec) */
- /* (error "Invalid Parameter to 'dir1'" filespec)))) */
- /* */
- /* Here, the Scheme function "dir1" checks its argument */
- /* to make sure that it's a string and, if it is, uses the */
- /* escape (%esc) opcode to invoke the function. If the */
- /* argument is not a string, an error is reported through */
- /* the Scheme error procedure. */
- /* */
- /* e. The Scheme runtime must be re-linked with your Borland */
- /* C and/or assembly language routines included. */
- /* The best would be to put all your code at the end of */
- /* this module. If you really need, you might make a new */
- /* module and link it with the others as follow : */
- /* Modify the MAKEFILE file (the compile-link edit control file) */
- /* to include your modules by adding them to the end of */
- /* the dependencies of PCS.EXE. */
- /* */
- /************************************************************************/
- /* */
- /* ESCAPE FUNCTIONS SUMMARY - please keep it up-to-date ! */
- /* ------------------------------------------------------- */
- /* */
- /* Part 1: Miscellanous functions */
- /* function code 0: find file match */
- /* function code 1: step through directory, matching files */
- /* function code 2: bid another MS-DOS task */
- /* function code 3: get the free space of heap */
- /* function code 4: scroll window up one line */
- /* function code 5: scroll window down one line */
- /* function code 6: split a filename into components (fnsplit) */
- /* function code 7: software interrupt */
- /* function code 8: float->hex conversion */
- /* function code 9: return hash value of symbol */
- /* function code 10: delete a file */
- /* function code 11: copy a file */
- /* function code 12: rename files under current directory */
- /* function code 13: sound specified frequency */
- /* function code 14: nosound (turn the speaker off) */
- /* function code 15: get the file size */
- /* function code 16: change current directory */
- /* function code 17: change current drive */
- /* function code 18: text-mode function call */
- /* function code 19: get path */
- /* function code 20: seed random number generator */
- /* function code 21: return compaction variable */
- /* function code 22: set compaction variable */
- /* Part 2: Math functions */
- /* function code 23: square root */
- /* function code 24: sinus */
- /* function code 25: cosinus */
- /* function code 26: tangent */
- /* function code 27: arctangent */
- /* function code 28: arccosinus */
- /* function code 29: arcsinus */
- /* function code 30: natural logarithm */
- /* function code 31: decimal logarithm */
- /* function code 32: base n logarithm */
- /* function code 33: exponential */
- /* function code 34: general exponent */
- /* Part 3: Other functions */
- /* function code 35: incremental global env lookup */
- /* function code 36: get env variable */
- /* function code 37: set env variable */
- /* function code 38: complete filename */
- /* function code 39: sprintf */
- /* function code 40: sscanf */
- /* function code 41: get cpu */
- /* function code 42: set cursor visibility when enabled (see 47) */
- /* function code 43: get clock */
- /* function code 44: get unix time */
- /* function code 45: convert to time structure */
- /* function code 46: convert from time structure */
- /* function code 47: set cursor auto-hiding off/on */
- /* */
- /************************************************************************/
-
- void schemetime( REGPTR r, struct tm *t )
- {
- REG temp;
-
- temp.page = ADJPAGE(SPECFIX);
- temp.disp = t->tm_isdst, cons( r, &temp, &nil_reg );
- temp.disp = t->tm_yday, cons( r, &temp, r );
- temp.disp = t->tm_wday, cons( r, &temp, r );
- temp.disp = t->tm_year, cons( r, &temp, r );
- temp.disp = t->tm_mon, cons( r, &temp, r );
- temp.disp = t->tm_mday, cons( r, &temp, r );
- temp.disp = t->tm_hour, cons( r, &temp, r );
- temp.disp = t->tm_min, cons( r, &temp, r );
- temp.disp = t->tm_sec, cons( r, &temp, r );
- }
-
- int link(LINKVAL *result, int lastArg, LINKARG arg[])
- {
- extern int compact_every; /* Indicates when to compact */
-
- /************************************************************************/
- /* Add a case entry in the following "switch" statement */
- /* to call your external procedure. The "case" number */
- /* is the function code which you must use to invoke your */
- /* function. */
- /************************************************************************/
- switch (arg[0].item.i) {
- case 0: /* function code 0: find file match */
- if ( ( result->s = (char *) malloc(24) ) != NULL )
- if ( dir1(arg[1].item.s, result->s) == NULL ) {
- free(result->s);
- result->s = NULL;
- }
- return STRorNIL;
- case 1: /* function code 1: step through directory, matching files */
- if ( ( result->s = (char *) malloc(24) ) != NULL )
- if ( dir2(0, result->s) == NULL ) {
- free(result->s);
- result->i = NULL;
- }
- return STRorNIL;
- case 2: /* function code 2: bid another MS-DOS task */
- result->i = bid_task(arg[1].item.s, arg[2].item.s, arg[3].item.s, arg[4].item.s);
- if (result->i == 0x8000)
- print_and_exit("[VM FATAL ERROR] DOS-CALL error: unable to restore PC Scheme memory\n");
- return INTEGER;
- case 3: /* function code 3: get the free space of heap */
- result->i = freesp();
- return INTEGER;
- case 4: /* function code 4: scroll window up one line */
- zscroll(arg[1].item.i, arg[2].item.i, arg[3].item.i, arg[4].item.i, arg[5].item.i);
- return NOVALUE;
- case 5: /* function code 5: scroll window down one line */
- zscroll_d(arg[1].item.i, arg[2].item.i, arg[3].item.i, arg[4].item.i, arg[5].item.i);
- return NOVALUE;
- case 6: /* function code 6: split a filename into its components */
- {
- char drive[MAXDRIVE], dir[MAXDIR], file[MAXFILE], ext[MAXEXT];
- int i;
-
- fnsplit(arg[1].item.s, drive, dir, file, ext);
- for ( i = 0; i < MAXDIR; i++ )
- if ( dir[i] == '\\' ) dir[i] = '/';
-
- result->s = (char *)malloc(MAXPATH + 10);
- sprintf(result->s, "(\"%s\"\"%s\"\"%s\"\"%s\")", drive, dir, file, ext);
- }
- return STR;
- case 7: /* function code 7: software interrupt */
- result->i = sw_int(arg[1].item.i, arg[3].item.i, arg[4].item.i, arg[5].item.i, arg[6].item.i);
- return arg[2].item.i;
- case 9: /* function code 9: return hash value of symbol */
- result->i = hash(arg[1].item.s, strlen(arg[1].item.s));
- return INTEGER;
- case 10: /* function code 10: delete a file */
- result->i = unlink(arg[1].item.s);
- return INTEGER;
- case 11: /* function code 11: copy a file */
- result->i = copy_file(arg[1].item.s, arg[2].item.s);
- return INTEGER;
- case 12: /* function code 12: rename files under current directory */
- result->i = rename(arg[1].item.s, arg[2].item.s);
- return INTEGER;
- case 13: /* function code 13: sound a specified frequency */
- sound(arg[1].item.i);
- return NOVALUE;
- case 14: /* function code 14: nosound (turn speaker off) */
- nosound();
- return NOVALUE;
- case 15: /* function code 15: get the file size */
- result->i = filesize(arg[1].item.s);
- return INTEGER;
- case 16: /* function code 16: change current directory */
- result->i = chdir(arg[1].item.s);
- return INTEGER;
- case 17: /* function code 17: change current drive */
- setdisk(toupper(*arg[1].item.s) - 'A');
- return NOVALUE;
- case 18: /* function code 18: textmode support */
- textmode(arg[1].item.i);
- return NOVALUE;
- case 19: /* function code 19: get path */
- if ( ( result->s = (char *) malloc(160) ) != NULL ) {
- int drv = toupper( *arg[1].item.s );
-
- strcpy( result->s, "?:\\");
- if( drv >= 'A')
- result->s[0] = drv;
- else
- result->s[0] = getdisk() + 'A';
- if( getcurdir( drv - '@', result->s + 3 ) )
- {
- free(result->s);
- result->s = NULL;
- }
- }
- return STRorNIL;
- case 20: /* function code 20: seed random number generator */
- if( ((signed) arg[1].item.i) == -1 )
- randomize();
- else srand(arg[1].item.i);
- return NOVALUE;
- case 22: /* function code 22: set compaction variable */
- compact_every = arg[1].item.i;
- case 21: /* function code 21: return compaction variable */
- result->i = compact_every;
- return INTEGER;
- case 23: /* function code 23: square root */
- result->f = sqrt (arg[1].item.f);
- return FLOAT;
- case 24: /* function code 24: sinus */
- result->f = sin (arg[1].item.f);
- return FLOAT;
- case 25: /* function code 25: cosinus */
- result->f = cos (arg[1].item.f);
- return FLOAT;
- case 26: /* function code 26: tangent */
- result->f = tan (arg[1].item.f);
- return FLOAT;
- case 27: /* function code 27: arctangent */
- if ( lastArg == 2 )
- result->f = atan2 (arg[1].item.f, arg[2].item.f);
- else
- result->f = atan (arg[1].item.f);
- return FLOAT;
- case 28: /* function code 28: arccosinus */
- result->f = acos (arg[1].item.f);
- return FLOAT;
- case 29: /* function code 29: arcsinus */
- result->f = asin (arg[1].item.f);
- return FLOAT;
- case 30: /* function code 30: natural log */
- result->f = log (arg[1].item.f);
- return FLOAT;
- case 31: /* function code 31: decimal log */
- result->f = log10 (arg[1].item.f);
- return FLOAT;
- case 32: /* function code 32: base n log */
- result->f = ( log (arg[1].item.f) / log (arg[2].item.f) );
- return FLOAT;
- case 33: /* function code 33: exponential */
- result->f = exp (arg[1].item.f);
- return FLOAT;
- case 34: /* function code 34: general exponent */
- result->f = pow (arg[1].item.f, arg[2].item.f);
- return FLOAT;
- case 35: /* incremental known symbols lookup */
- if( arg[1].item.i == -1 ) {
- matchdone();
- return NOVALUE;
- } else {
- REG kn_env;
-
- get_maxenv( &kn_env);
- result->s = ilookup( arg[1].item.s, arg[2].item.i, CORRPAGE(kn_env.page), kn_env.disp);
- return STRorNIL;
- }
- case 36: /* get env variable */
- {
- result->s = getenv( arg[1].item.s );
- return STATSTRorNIL;
- }
- case 37: /* set env variable */
- {
- result->i = putenv( arg[1].item.s );
- return INTEGER;
- }
- case 38: /* complete filename */
- {
- result->s = searchpath( arg[1].item.s );
- return STATSTRorNIL;
- }
- case 39: /* sprintf */
- {
- char *buf, newargs[NUM_REGS*sizeof(double)];
- char *p, *format;
- int i;
-
- if( (buf = (char *) malloc(2000)) == NULL )
- {
- printf_error: result->s = NULL;
- if( buf )
- free( buf );
- return STRorNIL;
- }
- if( arg[1].type != STR )
- goto printf_error;
- for( p = newargs, format = arg[1].item.s, i = 1; *format; format++ )
- if( *format == '%')
- {
- int longs = 0;
-
- if( *++format == '%')
- continue;
- if( ++i > lastArg )
- goto printf_error;
- for( int done = 0; !done; format++ )
- switch( *format )
- {
- case 0:
- case 'F': // pointers are invalid
- case 'N':
- case 'n':
- case 'L': // long doubles too
- goto printf_error;
- case 'h':
- longs = 0;
- case 'l':
- longs = 1;
- break;
- case '*':
- if( arg[i].type != INTEGER )
- goto printf_error;
- *((int *) p)++ = arg[i].item.i;
- if( ++i > lastArg )
- goto printf_error;
- break;
- case 's':
- if( arg[i].type != STR )
- goto printf_error;
- *((char **) p)++ = arg[i].item.s;
- done = 1;
- break;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'X':
- case 'x':
- if( arg[i].type != INTEGER )
- goto printf_error;
- if( longs )
- *((long *) p)++ = arg[i].item.i;
- else *((short *) p)++ = arg[i].item.b;
- done = 1;
- break;
- case 'E':
- case 'e':
- case 'f':
- case 'G':
- case 'g':
- if( arg[i].type != FLOAT )
- goto printf_error;
- *((double *) p)++ = arg[i].item.f;
- done = 1;
- break;
- case 'c':
- if( arg[i].type != CHARACTER )
- goto printf_error;
- *((int *) p)++ = arg[i].item.c;
- done = 1;
- break;
- }
- format--;
- }
- if( i != lastArg )
- goto printf_error;
-
- if( vsprintf( buf, arg[1].item.s, newargs ) == EOF )
- goto printf_error;
- result->s = buf;
- return STRorNIL;
- }
- case 40: /* sscanf */
- {
- REG r, s;
- LINKVAL *ptrs[NUMARGS];
- char *format;
- int i, args;
-
- if( arg[1].type != STR || arg[2].type != STR ||
- lastArg != 2 )
- {
- scanf_error: result->s = NULL;
- return BOOLEAN;
- }
- arg += 3; /* start with the first 'result' */
- for( format = arg[-1].item.s, i = -1; *format; format++ )
- if( *format == '%')
- {
- int longs = 0, zapit = 0;
-
- if( *++format == '%')
- continue;
- if( ++i >= NUMARGS )
- goto scanf_error;
- for( int done = 0; !done; format++ )
- switch( *format )
- {
- case 0:
- case 'F': // pointers are invalid
- case 'N':
- case 'n':
- case 'L': // long doubles too
- goto scanf_error;
- case 'h':
- longs = 0;
- case 'l':
- longs = 1;
- break;
- case '*':
- i--;
- zapit = 1;
- break;
- case 's':
- {
- if( !zapit )
- {
- int size = 0, mult = 1;
- char *f = format - 1;
- while( *f >= '0' && *f <= '9')
- {
- size += (*f-- - '0') * mult;
- mult *= 10;
- }
- if( size <= 0 )
- size = DEFSTR;
- if( !(ptrs[i] = (LINKVAL *) malloc(size+1)) )
- goto scanf_error;
- arg[i].type = STR;
- }
- done = 1;
- break;
- }
- case 'D':
- case 'd':
- case 'I':
- case 'i':
- case 'O':
- case 'o':
- case 'U':
- case 'u':
- case 'X':
- case 'x':
- if( !zapit )
- {
- ptrs[i] = &arg[i].item;
- arg[i].type = INTEGER;
- arg[i].item.i = 0;
- }
- done = 1;
- break;
- case 'E':
- case 'e':
- case 'f':
- case 'G':
- case 'g':
- if( !zapit )
- {
- if( !longs )
- goto scanf_error;
- ptrs[i] = &arg[i].item;
- arg[i].type = FLOAT;
- }
- done = 1;
- break;
- case 'c':
- if( !zapit )
- {
- ptrs[i] = &arg[i].item;
- arg[i].type = CHARACTER;
- }
- done = 1;
- break;
- }
- format--;
- }
- if( (args = vsscanf( arg[-2].item.s, arg[-1].item.s, ptrs )) == EOF )
- goto scanf_error;
- for( int k = i; k >= args; k-- ) /* free the unused args */
- if( arg[k].type == STR )
- free( ptrs[k] );
- r = nil_reg;
- for( k = args-1; k >= 0; k-- ) /* now actually return the stuff */
- {
- switch( arg[k].type )
- {
- case INTEGER:
- long2int( &s, arg[k].item.i );
- break;
- case FLOAT:
- alloc_flonum( &s, arg[k].item.f );
- break;
- case CHARACTER:
- s.page = ADJPAGE(SPECCHAR);
- s.disp = arg[k].item.c;
- break;
- case STR:
- alloc_string( &s, (char *) ptrs[k] );
- free( ptrs[k] );
- break;
- }
- cons( &r, &s, &r );
- }
- result->r = r;
- return SCHEME;
- }
- case 41: /* get cpu */
- {
- REG f1, f2;
- static unsigned ndp[] = { 0, 87, 287, 387 };
-
- f1.page = f2.page = ADJPAGE(SPECFIX);
-
- cputype( &f1, &f2 );
- cons( &f1, &f1, &f2 );
- f2.disp = ndp[_8087];
- {
- char far *p = (char far *) 0xf8000000;
- REG checksum;
- checksum.page = ADJPAGE(SPECFIX), checksum.disp = 0;
-
- for( unsigned i = 0; i < 0x8000; i++ )
- checksum.disp = checksum.disp * 7 + p[i];
- cons( &checksum, &checksum, &nil_reg );
- cons( &f2, &f2, &checksum );
- cons( &f1, &f1, &f2 );
- }
- result->r = f1;
- return SCHEME;
- }
- case 42: /* set cursor visibility when enabled */
- if (arg[1].item.i) {
- zputcur(arg[2].item.i, arg[3].item.i);
- zcuron();
- } else
- zcuroff();
- return NOVALUE;
- case 43: /* get clock */
- result->i = clock();
- return INTEGER;
- case 44: /* get unix time */
- result->i = time( NULL );
- return INTEGER;
- case 45: /* convert to time structure */
- schemetime( &result->r, (arg[1].item.i ? gmtime : localtime)( &arg[2].item.i ) );
- return SCHEME;
- case 46: /* convert from time structure */
- {
- struct tm t;
- t.tm_sec = arg[2].item.i;
- t.tm_min = arg[3].item.i;
- t.tm_hour = arg[4].item.i;
- t.tm_mday = arg[5].item.i;
- t.tm_mon = arg[6].item.i;
- t.tm_year = arg[7].item.i;
- result->i = mktime( &t );
- if( arg[1].item.i )
- {
- schemetime( &result->r, &t );
- return SCHEME;
- }
- return INTEGER;
- }
- case 47: /* automatic cursor hiding off/on */
- zautohiding(arg[1].item.i);
- return NOVALUE;
- default:
- return ERROR; /* unrecognized function code */
- }
- }